package com.itheima.manager;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.itheima.common.R;
import com.itheima.domain.*;
import com.itheima.exception.BusinessException;
import com.itheima.incerceptor.AdminHolder;
import com.itheima.service.*;
import com.itheima.util.JwtUtil;
import com.itheima.vo.PageBeanVo;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;

@Component
public class UmsAdminManager {
    @DubboReference
    IAdminService adminService;
    @DubboReference
    IAdminRoleRelationService adminRoleRelationService;
    @DubboReference
    IRoleService roleService;
    @DubboReference
    IMenuService menuService;
    @DubboReference
    IRoleMenuRelationService roleMenuRelationService;
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    //登录
    public R<Map<String, String>> login(Map<String, String> map) {
        //获取s用户名密码
        String username = map.get("username");
        String password = map.get("password");
        //查询管理员是否存在
        Admin one = adminService.findByUsername(username);

        //若不存在
        if (one == null) {
            throw new BusinessException("用户名输入错误");
        }

        //判断是否启用
        if(one.getStatus()==0){
            throw new BusinessException("用户未启用");
        }

        //判断密码是否正确
        if (!StrUtil.equals(one.getPassword(), SecureUtil.md5(password))) {
            System.out.println(SecureUtil.md5(password));
            throw new BusinessException("密码输入错误");
        }

        //将最后登录时间进行修改，存入数据库
        one.setLoginTime(LocalDateTime.now());
        adminService.updateLoginTime(one);

        one.setPassword(null);
        //生成token
        String token = JwtUtil.createToken(BeanUtil.beanToMap(one));

        //将token作为key,用户的json数组作为value写到redis中,时效1小时
        stringRedisTemplate.opsForValue().set(token, JSON.toJSONString(one), Duration.ofHours(1));
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("tokenHead", "Bearer ");
        resultMap.put("token", token);

        return R.success(resultMap);
    }

    //查询用户信息
    public R<Map<String, Object>> findAdminInfo(String name) {

        //获得登录者对象
        Admin admin = AdminHolder.get();
        if (admin == null) return R.error("错误");
        //获取id和icon
        Long id = admin.getId();
        String icon = admin.getIcon();

        //根据id查询用户角色对应关系表
        List<AdminRoleRelation> adminRoleRelations = adminRoleRelationService.findByAdminId(id);
        if (adminRoleRelations == null) {
            return R.error("用户没有分配角色");
        }

        //获取用户对应的角色id，并通过角色id查询角色名称,并将角色名称存入集合
        List<String> roleNames = new ArrayList<>();
        adminRoleRelations.forEach(roleRelation -> {
            Long roleId = roleRelation.getRoleId();
            Role role = roleService.findById(roleId);
            roleNames.add(role.getName());
        });

        //获取角色id，通过角色id查询角色id和菜单id的对应情况
        Set<RoleMenuRelation> roleMenuRelations = new HashSet<>();
        adminRoleRelations.forEach(roleRelation -> {
            Long roleId = roleRelation.getRoleId();
            //通过roleId查询对应的菜单id
            List<RoleMenuRelation> menuList = roleMenuRelationService.findByRoleId(roleId);
            roleMenuRelations.addAll(menuList);
        });

        //获取菜单id，查询菜单对象
        List<Menu> menus = new ArrayList<>();
        roleMenuRelations.forEach(roleMenuRelation -> {
            Long menuId = roleMenuRelation.getMenuId();
            //根据menuId查询菜单
            Menu menu = menuService.findById(menuId);
            menus.add(menu);
        });

        //将数据封装进map集合中
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("roles", roleNames);
        resultMap.put("icon", icon);
        resultMap.put("menus", menus);
        resultMap.put("username", admin.getUsername());
        return R.success(resultMap);
    }

    //退出登录
    public R<String> logout() {
        return R.success("退出成功");
    }

    //根据条件分页查询用户
    public R<PageBeanVo> findByPageAndKeyword(Integer pageNum, Integer pageSize, String keyword) {
        PageBeanVo pageBeanVo = adminService.findByPageAndKeyword(pageNum, pageSize, keyword);
        return R.success(pageBeanVo);
    }

    //注册
    public R<String> register(Admin admin) {
        Boolean result = adminService.saveAdmin(admin);
        if (result) {
            return R.success("添加成功");
        } else {
            return R.error("用户已存在");
        }
    }

    //根据用户id查询对应角色
    public R<List<Role>> findRoleByAdminId(Integer adminId) {
        List<AdminRoleRelation> adminRoleRelationList = adminRoleRelationService.findByAdminId(adminId.longValue());
        //遍历，获得对应角色id，查询角色,并存入集合
        List<Role> list = new ArrayList<>();
        if (adminRoleRelationList != null) {
            adminRoleRelationList.forEach(adminRoleRelation -> {
                Long roleId = adminRoleRelation.getRoleId();
                Role role = roleService.findById(roleId);
                list.add(role);
            });
        }
        return R.success(list);
    }

    //根据id删除指定用户
    public R<String> deleteById(Long id) {
        //将用户表中的用户删除
        adminService.deleteById(id);
        //将用户角色关系表中的相应关系删除
        adminRoleRelationService.deleteByAdminId(id);
        return R.success("删除成功");
    }

    //分配用户角色
    public R<String> updateRole(String adminId, String roleIds) {
        //先将用户角色关系表中对应用户的记录删除掉
        adminRoleRelationService.deleteByAdminId(Long.valueOf(adminId));

        //获取用户对应的新roleId
        List<Long> ids=new ArrayList<>();
        boolean b = roleIds.contains(",");
        if(b){
            String[] split = roleIds.split(",");
            for (String id : split) {
                ids.add(Long.valueOf(id));
            }
        }else{
            ids.add(Long.valueOf(roleIds));
        }
        //将用户id和对应的角色id加入用户角色关系表中
        ids.forEach(roleId->{
            AdminRoleRelation adminRoleRelation=new AdminRoleRelation();
            adminRoleRelation.setAdminId(Long.valueOf(adminId));
            adminRoleRelation.setRoleId(roleId);
            adminRoleRelationService.saveAdminRoleRelation(adminRoleRelation);
        });

        return R.success("分配角色成功");
    }

    public R<String> updateById(Admin admin) {
        //根据id修改用户信息
        adminService.updateAdmin(admin);
        return R.success("修改成功");
    }

    public R<String> updateStatus(Long id, Integer status) {
        //根据id修改用户状态
        adminService.updateStatus(id,status);
        return R.success("修改成功");
    }

    public R<Admin> findById(Long id) {

        Admin admin=adminService.findById(id);
        return R.success(admin);
    }

    public R<String> updatePassword(String oldPassword, String newPassword, String username) {

        //判断用户是否存在
        Admin admin = adminService.findByUsername(username);
        if(admin==null){
            return R.error("用户不存在");
        }
        //判断旧密码是否正确
        if(!StrUtil.equals(SecureUtil.md5(oldPassword),admin.getPassword())){
            return R.error("旧密码输入错误");
        }

        //设置新密码并存入数据库
        admin.setPassword(SecureUtil.md5(newPassword));
        adminService.updateAdmin(admin);
        return R.success("修改密码成功");
    }

    public R<Map<String,String>> refreshToken() {
        //获得登录用户的id
        Long id = AdminHolder.get().getId();
        //查询用户
        Admin admin = adminService.findById(id);
        //去掉重要信息
        admin.setPassword(null);

        //生成token
        String token = JwtUtil.createToken(BeanUtil.beanToMap(admin));

        //将token作为key,用户的json数组作为value写到redis中,时效1小时
        stringRedisTemplate.opsForValue().set(token, JSON.toJSONString(admin), Duration.ofHours(1));
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("tokenHead", "Bearer ");
        resultMap.put("token", token);

        return R.success(resultMap);
    }
}
